#include "client.h"

#define ERR_LOG(msg)                                      \
    do                                                    \
    {                                                     \
        cerr << __FILE__ << __func__ << __LINE__ << endl; \
        perror(msg);                                      \
    } while (false)

bool Client::doRegister()
{
    if (cfd_ < 0 || is_login_)
        return false;
    Msg msg, rdMsg; // 读写的消息结构体
    // 填写信息
    msg.type = REGISTER;
    cout << "请输入用户名(1-19且不含空格):";
    cin >> msg.name;
    cout << "请输入密码(1-127且不含空格):";
    cin >> msg.text;

    // 转换网络字节序
    msg.hton();

    // 发送给服务器
    if (send(cfd_, msg.Serialization().c_str(), Msg::getLen(), 0) < 0)
    {
        ERR_LOG("send error");
        return false;
    }
    // 接收信息
    char rbuf[Msg::getLen()] = "";
    if (recv(cfd_, rbuf, sizeof rbuf, 0) < 0)
    {
        ERR_LOG("recv error");
        return false;
    }
    rdMsg.Reserialization(rbuf); // 反序列化
    rdMsg.ntoh();                // 转换字节序
    // 判断是否注册成功
    if (rdMsg.type == REGISTER && strcmp(msg.name, rdMsg.name) == 0 && strcmp(rdMsg.text, "Register Success") == 0)
        return true;
    return false;
}

bool Client::doLogin()
{
    if (cfd_ < 0 || is_login_)
        return false;
    // 数据收发的结构体
    Msg msg, rdMsg;
    char rbuf[Msg::getLen()] = "";
    msg.type = LOGIN;
    cout << "请输入昵称(1-19且不包含空格):";
    cin >> msg.name;
    cout << "请输入密码(1-127且不包含空格):";
    cin >> msg.text;

    msg.hton();
    // 发送消息
    if (send(cfd_, msg.Serialization().c_str(), Msg::getLen(), 0) < 0)
    {
        ERR_LOG("send error");
        return false;
    }

    if (recv(cfd_, rbuf, sizeof rbuf, 0) < 0)
    {
        ERR_LOG("recv error");
        return false;
    }

    rdMsg.Reserialization(rbuf);
    rdMsg.ntoh();
    // 判断返回的消息是否正确
    if (rdMsg.type == LOGIN && strcmp(rdMsg.name, msg.name) == 0 && strcmp(rdMsg.text, "Login Success") == 0)
    {
        is_login_ = true; // 设置为登录状态
        username_ = rdMsg.name;
        return true;
    }
    return false;
}

void Client::doQuerry()
{
    if (!is_login_ || cfd_ < 0)
        return;
    Msg msg, rdMsg;
    char rbuf[Msg::getLen()] = "";

    msg.type = SELECT;
    strcpy(msg.name, username_.c_str());
    msg.ntoh();

    while (true)
    {
        cout << "请输入要查询的单词(输入#结束查询):";
        cin.getline(msg.text, sizeof msg.text);
        if (strcmp(msg.text, "#") == 0)
            break;

        if (send(cfd_, msg.Serialization().c_str(), Msg::getLen(), 0) < 0)
        {
            ERR_LOG("send error");
            continue;
        }
        if (recv(cfd_, rbuf, sizeof rbuf, 0) < 0)
        {
            ERR_LOG("recv error");
            continue;
        }

        rdMsg.Reserialization(rbuf);
        rdMsg.ntoh();

        if (rdMsg.type == SELECT && strcmp(rdMsg.name, username_.c_str()) == 0)
        { // 输出返回来的信息
            cout << "翻译：" << rdMsg.text << endl;
        }
        else
        {
            cout << "type: " << rdMsg.type << " name: " << rdMsg.name << " text: "<< rdMsg.text << endl;
            puts("出现未知错误!");
        }
    }
}

void Client::doHistory()
{
    if (!is_login_ || cfd_ < 0)
        return;
    Msg msg;
    char rbuf[Msg::getLen()] = "";

    // 填写信息
    msg.type = HISTORY;
    strcpy(msg.name, username_.c_str());
    msg.hton();

    if (send(cfd_, msg.Serialization().c_str(), Msg::getLen(), 0) < 0)
    {
        ERR_LOG("send error");
        return;
    }
    puts("查询历史记录：");
    while (true)
    {
        if (recv(cfd_, rbuf, sizeof rbuf, 0) < 0)
        {
            ERR_LOG("recv error");
            return;
        } // 读取信息

        msg.Reserialization(rbuf);
        msg.ntoh();

        // 查询到历史记录后输出
        if (msg.type == HISTORY && strcmp(msg.name, username_.c_str()) == 0)
        {
            cout << msg.text;
            if(strcmp(msg.text, "Send Over") == 0)
                break;
        }
        else
        {
            cout << "type: " << msg.type << " name: " << msg.name << " text: " << msg.text << endl;
            puts("未知错误");
            break;
        }
    }
}

bool Client::doQuit()
{
    if (!is_login_ || cfd_ < 0)
        return false;
    Msg msg;
    char rbuf[Msg::getLen()] = "";
    msg.type = LOGOUT;
    strcpy(msg.name, username_.c_str());

    msg.hton();

    if (send(cfd_, msg.Serialization().c_str(), Msg::getLen(), 0) < 0)
    {
        ERR_LOG("send error");
        return false;
    }


    if(recv(cfd_, rbuf, sizeof rbuf, 0) < 0)
    {
        ERR_LOG("recv error");
        return false;
    }

    msg.Reserialization(rbuf);
    msg.ntoh();
    if (msg.type == LOGOUT && strcmp(msg.name, username_.c_str()) == 0 && strcmp(msg.text, "Logout Success") == 0)
    {
        is_login_ = false;
        return true;
    }
    return false;
}

void Client::run()
{
    if (cfd_ < 0)
        return;

    char x = '1';
    while (true)
    {
        system("cls");
        showMainView(); // 展示主菜单 --- 登录，注册，退出
        cin >> x;       // 读取
        cin.ignore();   // 清清除输入缓冲区
        if (x == '1')
        {
            if (doRegister())
                cout << "注册成功!\n";
            else
                cout << "注册失败!\n";
        }
        else if (x == '2')
        {
            if (doLogin())
            { // 登录成功后进入用户界面
                showUserMenu();
            }
            else
                cout << "登录失败!\n";
        }
        else if (x == '0') // 此时还没有登录，所以是直接退出
        {
            break;
        }
        else
        {
            cout << "非法输入\n";
        }
        cout << "请输入回车继续...";
        cin.get();
    }
}

void Client::showMainView()
{
    system("clear");
    cout << "* 网络电子词典 *\n"
            "* 1.注册       *\n"
            "* 2.登录       *\n"
            "* 0.退出       *\n"
            "请选择：";
}

void Client::showUserMenu()
{
    while (is_login_)
    {
        system("clear");
        cout << "* 网络电子词典 *\n"
                "* 1.单词查询   *\n"
                "* 2.历史记录   *\n"
                "* 0.登出       *\n"
                "请选择：";

        char x;
        cin >> x;
        cin.ignore();

        if (x == '1')
        {
            doQuerry();
        }
        else if (x == '2')
        {
            doHistory();
        }
        else if (x == '0')
        {
            if(doQuit())
            break;
            else
                puts("登出失败!");
        }
        else
            cout << "非法输入\n";

        cout << "请输入回车继续...";
        cin.get();
    }
}

Client::Client(const string &ip, short port) : is_login_(false)
{
    if (connectToServer(ip, port) == false)
        throw runtime_error("connectToServer error");
}

Client::~Client()
{
    if (cfd_ >= 0)
    {
        doQuit();    // 退出
        close(cfd_); // 关闭套接字
    }
}

// 网络连接函数的定义
bool Client::connectToServer(const string &ip, short port)
{
    cfd_ = socket(AF_INET, SOCK_STREAM, 0);

    if (cfd_ < 0)
    {
        ERR_LOG("socker error");
        return false;
    }

    // 填写地址结构体
    caddr_.sin_addr.s_addr = inet_addr(ip.c_str());
    caddr_.sin_port = htons(port);
    caddr_.sin_family = AF_INET;

    // 进行连接
    if (connect(cfd_, (sockaddr *)&caddr_, sizeof caddr_) < 0)
    {
        ERR_LOG("connect error");
        return false;
    }
    return true;
}